#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/stat.h>

#define NUM 1024
#define SIZE 32

#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3
#define NONE_REDIR 0

char* g_argv[SIZE];
char cmd_line[NUM];

char g_myval[64];

int redir_status = NONE_REDIR;
char* CheckRedir(char* start)
{
    assert(start);
    char* end = start + strlen(start) -1;//ls -a -l\0
    while(end >= start)
    {
        if(*end == '>')
        {
            //ls -a -l>log.txt
            //ls -a -l>>log.txt
            if(*(end - 1) == '>')//追加重定向
            {
                redir_status = APPEND_REDIR;
                *(end - 1) = '\0';
                end++;
                //将end指向文件名字符串起始地址
                break;
            }
            //输出重定向
            redir_status = OUTPUT_REDIR;
            *end = '\0';
            end++;
            break;
        }
        else if(*end == '<')
        {
            redir_status = INPUT_REDIR;
            *end = '\0';
            end++;
            break;
        }
        else   
        end--;
    }
    if(end >= start)
    {
        return end;
    }
    else 
    {
        return NULL;
    }
}
int main()
{
    while(1)
    {
        //1. 打印出提示信息 [csd@localhost myshell]# 
        printf("[csd@host_local_myshell]$ ");
        fflush(stdout);
        memset(cmd_line,'\0',sizeof cmd_line);

         //2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
        if(fgets(cmd_line,sizeof cmd_line,stdin) == NULL)
        {
            continue;
        }
        
        //"ls -a -l -i\n\0"
        cmd_line[strlen(cmd_line) - 1] = '\0';//将'\n'改为'\0'
        
        char* file = CheckRedir(cmd_line);
        //strtok函数 对原字符串按需求切割
        //3. 命令行字符串解析："ls -a -l -i" -> "ls" "-a" "-i"
        g_argv[0] = strtok(cmd_line," ");//第一次调用strtok要传入原始字符串
        int index = 1;

        if(strcmp(g_argv[0],"ls") == 0)
        {
            g_argv[index++] =(char*) "--color=auto";
        }

        if(strcmp(g_argv[0],"ll") == 0)
        {
            g_argv[0] =(char*)"ls";
            g_argv[index++] = (char*)"-l";
            g_argv[index++] = (char*)"--color=auto";
        }

        while(g_argv[index++] = strtok(NULL," "));//继续调用strtok，只需传入NULL
        //让父进程（shell）自己执行的命令，叫内置命令，内置命令是不需要创建子进程，让子进程去执行的
        //内置命令本质上是一个shell中的函数调用
        if(strcmp(g_argv[0],"export") == 0)
        {
            strcpy(g_myval,g_argv[1]);
            putenv(g_myval);
          // putenv(g_argv[1]);
        }

        if(strcmp(g_argv[0],"cd" ) == 0 )
        {
            if(g_argv[1] != NULL) chdir(g_argv[1]);
            continue;
        }

        pid_t id = fork();
        if(id == 0)
        {
            if(file != NULL)
            {
                int fd = -1;
                switch(redir_status)
                {
                    case INPUT_REDIR:
                        fd = open(file,O_RDONLY);
                        dup2(fd,0);
                        break;
                    case OUTPUT_REDIR:
                        fd = open(file,O_WRONLY | O_TRUNC | O_CREAT,0666);
                        if(fd < 0) 
                        {
                            perror("open");
                            return 1;
                        }
                        dup2(fd,1);//重定向 

                        break;
                    case APPEND_REDIR:
                        fd = open(file,O_WRONLY | O_APPEND | O_CREAT,0666);
                        dup2(fd,1);
                        break;
                    default:
                        printf("bug\n");
                        break;
                }
            }
           // printf("%s\n",getenv("MYVAL"));    
            execvp(g_argv[0],g_argv);
            exit(1);
        }
        else 
        {
            int status = 0;
            pid_t res = waitpid(id,&status,0);
            if(res > 0)
                printf("exit code : %d\n",WEXITSTATUS(status));
        }
    }
    return 0;
}
